// 条件类型  if / else 三元表达式  (extends 左边 和 右边的关系)........................ 条件类型....................................
// 和泛型约束通常一起使用，类似三元运算符， 泛型约束是用来约束泛型的《也包含了判断)， 条件是用来判断的
// 子类型 extends 父类型 = true   T extends 200 | 204 | 206 ? "success" : "faiL"; 是三元表达式
// <T extends number>是类型约束
type ResStatusMessage<T extends number> = T extends 200 | 204 | 206
  ? "success"
  : "fail";
type Rl = ResStatusMessage<200>;
type Conditional<T, U> = T extends U ? "success" : "fail";
type R2 = Conditional<"jiangwen", string>;
type R3 = Conditional<"jiangwen", number>;

interface Bird {
  name: "鸟";
}
interface sky {
  name: "天";
}
interface Fish {
  name: "鱼";
}
interface Water {
  name: "水";
}
type conditional1<T> = T extends Bird ? sky : Water;
type R4 = conditional1<Fish>;

//泛型一般代表输入是不确定的(无限的) 要加约束;
// 条件有限的,用函数重载,这样就可以避免很多函数内部的if else判断
// 这个是返回值的类型
type FormatReturnVal<T extends string | number> = T extends string
  ? string
  : T extends number
  ? number
  : never;
function sum1<T extends string | number>(a: T, b: T): FormatReturnVal<T> {
  // 泛型类型不能做 数学运算 ====> T+T=? 这样是不行的
  return a + (b as any);
}
let r0 = sum1(1, 2);
//我们知道了 条件运算符 就可以掌握ts中的兼容性 以及类型的层级..................................兼容性.................................
// 兼容性 就是可以将一个值赋予给某个值
// 类型层级:低的层级可以赋予给高的层级

// 兼容性
//字面量类型可以赋予给基础类型
type R11 = "abc" extends string ? true : false;
type R12 = 123 extends number ? true : false;
type R13 = true extends boolean ? true : false;
// 下面是实战
let r11: string = "abc";
let r12: number = 123;
//字面类型可以赋予给字面量的联合类型
type R14 = "a" extends "a" | "b" | "c" ? true : false;
type R5 = 1 extends 1 | 2 | 3 ? true : false;
type R6 = true extends true | false ? true : false;
// 下面是实战
let r4: "a" | "b" | "c" = "a";

// 基础类型是包装类型的子类型
type R7 = string extends String ? true : false;
type R8 = number extends Number ? true : false;
type R9 = boolean extends Boolean ? true : false;
type R10 = boolean extends Object ? true : false;
type R111 = Object extends any ? true : false;
type R122 = Object extends unknown ? true : false;
type R133 = never extends "abc" ? true : false;
// never 是最新的类型
// 字面类型可以赋予给字面量的联合类型
// 字面量类型可以赋予给基础类型
//  基础类型是包装类型的子类型
// any unknwon 是最大类型
// never < 字面量 < 字面量联合类型 | 字面量类型 < 基础數据类型 < 包裝类型 < Object < any | unknown
//针对any 来说 永远返回的结果是成功和失败的联合类型
type R144 = any extends 1 ? true : false; // true | false -> boolean

type R15 = unknown extends "abc" ? true : false; // false

type R16 = any extends any ? true : false; // 自己和自己比不会出错
//类型层面上的，低类型 可以赋予高类型
//从结构上考虑的交叉类型 可以赋予 交叉前的类型
//{}(字面量，也是一个空对象)object(只能赋予对象)Object(万物皆对象)
type R17 = {} extends object ? true : false;
type R18 = {} extends Object ? true : false;
// 结构上考虑

type R19 = object extends {} ? true : false;
type R20 = Object extends {} ? true : false;
//ts 默认 小的object 和 Object 都可以相互赋值
type R21 = Object extends object ? true : false;
type R22 = object extends Object ? true : false;
//结构上是不是比你多，比你多的就兼容
//看级别，我的级别比你低就可以赋予给你

export {};

type StatusCode<T> = T extends 200 | 201 | 204 | 304 ? "success" : "fail";
type IReturnMessage = StatusCode<200>;

type IObj<T> = T extends { name: "jw" } ? "ok" : "no ok";
type IPerson = IObj<{ name: "jw"; age: 30 }>;
type IPerson1 = IObj<{}>;
// 类型级别 1) 根据结构的角度来分析  2) 从类型角度来进行分析

//  never 是任何类型的子类型
//  字面量类型
//  基础类型
//  包装的类型
//  any unknown

type T1 = never extends "str" ? true : false;
type T2 = "str" extends string ? true : false;
type T3 = string extends String ? true : false;

// {} object Object   {} 和 object 可以看成字面量类型

type Temp1 = {} extends object ? true : false;
type Temp2 = object extends {} ? true : false;
type Temp3 = object extends Object ? true : false;
type Temp4 = Object extends object ? true : false; // 因为从结构角度出发
type Temp5 = Object extends {} ? true : false;
type Temp6 = object extends {} ? true : false;

// {}  object 可以看成结构， 和类型两部分

type T4 = string extends object ? true : false;

type T5 = string extends any ? true : false;
type T6 = string extends unknown ? true : false;

type T7 = any extends unknown ? true : false;
type T8 = unknown extends any ? true : false;

type T9 = any extends 1 ? true : false; // (条件类型 是有分发机制) 1 + 除了1的部分  true ｜ false

// any自带分发的机制
// never 如果通过泛型传入，此时只会返回never
type T10<T> = never extends string ? true : false;
type Temp7 = T10<never>;

// 联合类型的子类型 是联合类型中的某个类型
type T11 = 100 extends 100 | 200 ? true : false;

// 通过条件类型 来进行类型的区分，条件语句也可以实现约束的效果

interface Fish {
  name: "鱼";
}
interface Bird {
  name: "鸟";
}
interface Water {
  name: "水";
}
interface Sky {
  name: "天";
}

// T & {} 就可以解决分发问题
type GetType<T extends Fish | Bird> = T & {} extends Fish ? Water : Sky;
// 分发导致的问题： 什么时候会有分发
// 1.联合类型通过泛型传递
// 2.而且比较(extends)的时候会产生分发
// 3.类型需要是裸类型 (裸类型就是泛型 就自己没有和别人搭配)

type A1 = GetType<Fish | Bird>;

type NoDistribute<T> = T & {};

// 分发机制有的场景需要，有的场景需要禁用， 不能一概而论。
type UnionAssets<T, K> = NoDistribute<T> extends K ? true : false;
type U1 = UnionAssets<1 | 2, 1 | 2 | 3>;
type U2 = UnionAssets<1 | 2 | 3, 1 | 2>;

// 判断两个类型是否完全一致 ？   1|2    1|2

type isEqual<T, K, S, F> = NoDistribute<T> extends K
  ? NoDistribute<K> extends T
    ? S
    : F
  : F;
type A2 = isEqual<1 | 2, 1 | 2, true, false>;

type FormatVal<T> = T extends string
  ? string
  : T extends number
  ? number
  : never;

// 映射关系 可以考虑用泛型，参数个数不一致，类型和入参数无法，考虑重载
function sum<T extends string | number>(a: T, b: T): FormatVal<T> {
  return a + (b as any);
}
let r = sum(1, 2);

// 子类型  父类型

// 内置类型中有很多类型是基于条件类型的
// Extract Exclude , NonNullable...

type Extract<T, U> = T extends U ? T : never;
type ExtractRes = Extract<1 | 2 | 3 | 4, 1 | 2>;
type Exclude<T, U> = T extends U ? never : T;
type ExcludeRes = Exclude<1 | 2 | 3 | 4, 1 | 2>;

const ele = document.getElementById("app");
// type NonNullable<T> = T extends null | undefined ? never : T;
// type NonNullable<T> = T & {};
type Ele = NonNullable<typeof ele>;

export {};
